package com.garbuz.svnadmin;

import com.garbuz.svnadmin.services.ServiceBase;
import common.utils.ReflectUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ServiceInvoker
{
	private Throwable error;

	private String servicesPackage;

	public ServiceInvoker(String servicesPackage)
	{
		this.servicesPackage = servicesPackage;
	}

	public Object invoke(String serviceName, String methodName,  Object[] arguments)
	{
		Object result = null;

		try
		{
			String className = servicesPackage + "." + serviceName;
			Class<?> serviceClass = Class.forName(className);
			ServiceBase service = (ServiceBase) serviceClass.newInstance();

			Class[] argsTypes = ReflectUtil.getTypes(arguments);
			Method method = service.getClass().getMethod(methodName, argsTypes);

			result = method.invoke(service, arguments);
		}
		catch (InvocationTargetException e)
		{
			error = getTargetError(e);
		}
		catch (Throwable e)
		{
			error = e;
		}

		return result;
	}

	protected Throwable getTargetError(Throwable e)
	{
		while (e instanceof InvocationTargetException)
		{
			e = ((InvocationTargetException) e).getTargetException();
		}

		return e;
	}

	public static String getErrorText(Throwable e, String filter)
	{
		StringBuilder sb = new StringBuilder();

		while (e != null)
		{
			sb.append(e.toString());

			StackTraceElement[] stackElements = e.getStackTrace();

			for (StackTraceElement item : stackElements)
			{
				String stackItem = item.toString();
				if (filter == null || stackItem.startsWith(filter))
					sb.append("\n").append(stackItem);
			}

			e = e.getCause();

			if (e != null)
				sb.append("\n");
		}

		return sb.toString();
	}

	/*///////////////////////////////////////////////////////////////////////////////////
	//
	// get/set
	//
	///////////////////////////////////////////////////////////////////////////////////*/

	public Throwable getError()
	{
		return error;
	}

	public boolean successful()
	{
		return (error == null);
	}
}
